home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _2E3901B0DDF349A992C60A4B12B957EB < prev    next >
Encoding:
Text File  |  2002-07-02  |  30.5 KB  |  1,371 lines

  1. // Copyright (C) 2001-2002 Raven Software.
  2. //
  3. // g_combat.c
  4.  
  5. #include "g_local.h"
  6.  
  7. void BotDamageNotification    ( gclient_t *bot, gentity_t *attacker );
  8.  
  9. /*
  10. ============
  11. G_AddScore
  12.  
  13. Adds score to both the client and his team
  14. ============
  15. */
  16. void G_AddScore( gentity_t *ent, int score ) 
  17. {
  18.     if ( !ent->client ) 
  19.     {
  20.         return;
  21.     }
  22.     
  23.     // no scoring during pre-match warmup
  24.     if ( level.warmupTime ) 
  25.     {
  26.         return;
  27.     }
  28.  
  29.     ent->client->sess.score += score;
  30.     ent->client->ps.persistant[PERS_SCORE] = ent->client->sess.score;
  31.  
  32.     CalculateRanks();
  33. }
  34.  
  35. /*
  36. =================
  37. TossClientItems
  38.  
  39. Toss the weapon and custom gametype items for the killed player
  40. =================
  41. */
  42. void TossClientItems( gentity_t *self ) 
  43. {
  44.     int    weapon;
  45.  
  46.     // drop the weapon if not a gauntlet or machinegun
  47.     weapon = self->s.weapon;
  48.  
  49.     // make a special check to see if they are changing to a new
  50.     // weapon that isn't the mg or gauntlet.  Without this, a client
  51.     // can pick up a weapon, be killed, and not drop the weapon because
  52.     // their weapon change hasn't completed yet and they are still holding the MG.
  53.     if ( self->client->ps.weaponstate == WEAPON_DROPPING ) 
  54.     {
  55.         weapon = self->client->pers.cmd.weapon;
  56.     }
  57.         
  58.     if ( !( self->client->ps.stats[STAT_WEAPONS] & ( 1 << weapon ) ) ) 
  59.     {
  60.         weapon = WP_NONE;
  61.     }
  62.     
  63.     // If we have a valid weapon to drop and it has ammo then drop it
  64.     if ( weapon > WP_KNIFE && weapon < WP_NUM_WEAPONS &&
  65.          (self->client->ps.ammo[ weaponData[weapon].attack[ATTACK_NORMAL].ammoIndex ] + self->client->ps.clip[weapon]) ) 
  66.     {
  67.         G_DropWeapon ( self, weapon, 0 );
  68.     }
  69.  
  70.     G_DropGametypeItems ( self );
  71. }
  72.  
  73. /*
  74. ==================
  75. LookAtKiller
  76. ==================
  77. */
  78. void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) {
  79.     vec3_t        dir;
  80.     vec3_t        angles;
  81.  
  82.     if ( attacker && attacker != self ) {
  83.         VectorSubtract (attacker->s.pos.trBase, self->s.pos.trBase, dir);
  84.     } else if ( inflictor && inflictor != self ) {
  85.         VectorSubtract (inflictor->s.pos.trBase, self->s.pos.trBase, dir);
  86.     } else {
  87.         self->client->ps.stats[STAT_DEAD_YAW] = self->s.angles[YAW];
  88.         return;
  89.     }
  90.  
  91.     self->client->ps.stats[STAT_DEAD_YAW] = vectoyaw ( dir );
  92.  
  93.     angles[YAW] = vectoyaw ( dir );
  94.     angles[PITCH] = 0; 
  95.     angles[ROLL] = 0;
  96. }
  97.  
  98. /*
  99. ==================
  100. body_die
  101. ==================
  102. */
  103. void body_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath, int hitLocation, vec3_t hitDir ) 
  104. {
  105.     return;
  106. }
  107.  
  108.  
  109. // these are just for logging, the client prints its own messages
  110. char *modNames[] = 
  111. {
  112.     "MOD_UNKNOWN",
  113.  
  114.     "MOD_KNIFE",
  115.  
  116.     "MOD_M1911A1_PISTOL",
  117.     "MOD_US_SOCOM_PISTOL",         
  118.  
  119.     "MOD_M590_SHOTGUN",            
  120.     "MOD_MICRO_UZI_SUBMACHINEGUN", 
  121.     "MOD_M3A1_SUBMACHINEGUN",      
  122.     "MOD_MP5",
  123.  
  124.     "MOD_USAS_12_SHOTGUN",         
  125.     "MOD_M4_ASSAULT_RIFLE",        
  126.     "MOD_AK74_ASSAULT_RIFLE",      
  127.     "MOD_MSG90A1_SNIPER_RIFLE",    
  128.     "MOD_M60_MACHINEGUN",          
  129.     "MOD_MM1_GRENADE_LAUNCHER",    
  130.     "MOD_RPG7_LAUNCHER",           
  131.  
  132.     "MOD_M84_GRENADE",
  133.     "MOD_SMOHG92_GRENADE",
  134.     "MOD_ANM14_GRENADE",
  135.     "MOD_M15_GRENADE",
  136.  
  137.     "MOD_WATER",
  138.     "MOD_CRUSH",
  139.     "MOD_TELEFRAG",
  140.     "MOD_FALLING",
  141.     "MOD_SUICIDE",
  142.     "MOD_TEAMCHANGE",
  143.     "MOD_TARGET_LASER",
  144.     "MOD_TRIGGER_HURT",
  145.     "MOD_TRIGGER_HURT_NOSUICIDE"
  146. };
  147.  
  148. /*
  149. ==================
  150. player_die
  151. ==================
  152. */
  153. void player_die( 
  154.     gentity_t    *self, 
  155.     gentity_t    *inflictor, 
  156.     gentity_t    *attacker, 
  157.     int            damage, 
  158.     int            mod, 
  159.     int            hitLocation,
  160.     vec3_t        hitDir
  161.     ) 
  162. {
  163.     gentity_t        *ent;
  164.     int                anim;
  165.     int                contents;
  166.     int                killer;
  167.     int                i;
  168.     char            *killerName, *obit;
  169.     attackType_t    attack;
  170.     int                meansOfDeath;
  171.  
  172.     attack         = (mod >> 8) & 0xFF;
  173.     meansOfDeath = mod & 0xFF;
  174.  
  175.     if ( self->client->ps.pm_type == PM_DEAD ) 
  176.     {
  177.         return;
  178.     }
  179.  
  180.     if ( level.intermissiontime ) 
  181.     {
  182.         return;
  183.     }
  184.  
  185.     // Let the gametype know about the player death so it can adjust anything
  186.     // it needs to adjust
  187.     if ( attacker && attacker->client )
  188.     {
  189.         trap_GT_SendEvent ( GTEV_CLIENT_DEATH, level.time, self->s.number, self->client->sess.team, attacker->s.number, attacker->client->sess.team, 0 ); 
  190.     }
  191.     else
  192.     {
  193.         trap_GT_SendEvent ( GTEV_CLIENT_DEATH, level.time, self->s.number, self->client->sess.team, -1, -1, 0 ); 
  194.     }
  195.  
  196.     // Add to the number of deaths for this player
  197.     self->client->sess.deaths++;
  198.  
  199.     // This is just to ensure that the player wont render for even a single frame
  200.     self->s.eFlags |= EF_DEAD;
  201.  
  202.     self->client->ps.pm_type = PM_DEAD;
  203.  
  204.     if ( attacker ) 
  205.     {
  206.         killer = attacker->s.number;
  207.         if ( attacker->client ) 
  208.         {
  209.             killerName = attacker->client->pers.netname;
  210.         } 
  211.         else 
  212.         {
  213.             killerName = "<non-client>";
  214.         }
  215.     } 
  216.     else 
  217.     {
  218.         killer = ENTITYNUM_WORLD;
  219.         killerName = "<world>";
  220.     }
  221.  
  222.     if ( killer < 0 || killer >= MAX_CLIENTS ) 
  223.     {
  224.         killer = ENTITYNUM_WORLD;
  225.         killerName = "<world>";
  226.     }
  227.  
  228.     if ( meansOfDeath < 0 || meansOfDeath >= sizeof( modNames ) / sizeof( modNames[0] ) ) 
  229.     {
  230.         obit = "<bad obituary>";
  231.     } 
  232.     else 
  233.     {
  234.         if ( attack == ATTACK_ALTERNATE )
  235.         {
  236.             obit = va ( "%s_ALT", modNames[ meansOfDeath ] );
  237.         }
  238.         else
  239.         {
  240.             obit = modNames[ meansOfDeath ];
  241.         }
  242.     }
  243.  
  244.     // If the weapon was charging then drop it with no forward velocity
  245.     if ( self->client->ps.grenadeTimer )
  246.     {
  247.         gentity_t* missile;
  248.         missile = G_FireWeapon( self, ATTACK_NORMAL );
  249.         missile->dflags |= DAMAGE_NO_TEAMKILL;
  250.         if ( missile )
  251.         {
  252.             VectorClear ( missile->s.pos.trDelta );
  253.         }
  254.     }
  255.  
  256.     G_LogPrintf("Kill: %i %i %i: %s killed %s by %s\n", 
  257.         killer, self->s.number, meansOfDeath, killerName, 
  258.         self->client->pers.netname, obit );
  259.  
  260.     // broadcast the death event to everyone
  261.     ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY );
  262.     ent->s.eventParm = mod;
  263.     ent->s.otherEntityNum = self->s.number;
  264.     ent->s.otherEntityNum2 = killer;
  265.     ent->r.svFlags = SVF_BROADCAST;    // send to everyone
  266.  
  267.     self->enemy = attacker;
  268.  
  269.     if (attacker && attacker->client) 
  270.     {
  271.         attacker->client->lastkilled_client = self->s.number;
  272.  
  273.         if ( attacker == self )
  274.         {
  275.             if ( mod != MOD_TEAMCHANGE && mod != MOD_TRIGGER_HURT_NOSUICIDE )
  276.             {
  277.                 G_AddScore( attacker, g_suicidePenalty.integer );
  278.             }
  279.         } 
  280.         else if ( OnSameTeam ( self, attacker ) ) 
  281.         {
  282.             if ( mod != MOD_TELEFRAG && mod != MOD_TRIGGER_HURT_NOSUICIDE )
  283.             {
  284.                 G_AddScore( attacker, g_teamkillPenalty.integer );
  285.             }
  286.         }
  287.         else 
  288.         {
  289.             G_AddScore( attacker, 1 );
  290.             attacker->client->sess.kills++;
  291.     
  292.             attacker->client->lastKillTime = level.time;
  293.         }
  294.     }
  295.     else if ( mod != MOD_TEAMCHANGE && mod != MOD_TRIGGER_HURT_NOSUICIDE )
  296.     {
  297.         G_AddScore( self, g_suicidePenalty.integer );
  298.     }
  299.  
  300.     // If client is in a nodrop area, don't drop anything
  301.     contents = trap_PointContents( self->r.currentOrigin, -1 );
  302.     if ( !( contents & CONTENTS_NODROP ) ) 
  303.     {
  304.         // People who kill themselves dont drop guns
  305.         if ( attacker == self )
  306.         {
  307.             self->client->ps.stats[STAT_WEAPONS] = 0;
  308.         }
  309.  
  310.         TossClientItems( self );
  311.     }
  312.     else 
  313.     {
  314.         // Any gametype items that are dropped into a no drop area need to be reported
  315.         // to the gametype so it can handle it accordingly
  316.         for ( i = 0 ; i < MAX_GAMETYPE_ITEMS ; i++ ) 
  317.         {
  318.             gitem_t* item;
  319.  
  320.             // skip this gametype item if the client doenst have it
  321.             if ( !(self->client->ps.stats[STAT_GAMETYPE_ITEMS] & (1<<i)) ) 
  322.             {
  323.                 continue;
  324.             }
  325.  
  326.             item = BG_FindGametypeItem ( i );
  327.  
  328.             // Let the gametype handle the problem, if it doenst handle it and return 1 then 
  329.             // just reset the gametype item
  330.             if ( !trap_GT_SendEvent ( GTEV_ITEM_STUCK, level.time, level.gametypeItems[item->giTag].id, 0, 0, 0, 0 ) )
  331.             {
  332.                 G_ResetGametypeItem ( item );
  333.             }
  334.         }
  335.     }
  336.  
  337.     Cmd_Score_f( self );
  338.  
  339.     // send updated scores to any clients that are following this one,
  340.     // or they would get stale scoreboards
  341.     for ( i = 0 ; i < level.numConnectedClients; i++ ) 
  342.     {
  343.         gclient_t    *client;
  344.  
  345.         client = g_entities[level.sortedClients[i]].client;
  346.  
  347.         if ( client->pers.connected != CON_CONNECTED )
  348.         {
  349.             continue;
  350.         }
  351.         
  352.         if ( !G_IsClientSpectating ( client ) ) 
  353.         {
  354.             continue;
  355.         }
  356.         
  357.         if ( client->sess.spectatorClient == self->s.number ) 
  358.         {
  359.             Cmd_Score_f( g_entities + i );
  360.         }
  361.     }
  362.  
  363.     self->s.weapon                    = WP_NONE;
  364.     self->s.gametypeitems            = 0;
  365.  
  366.     // no gibbing right now
  367. //    self->r.contents                = CONTENTS_CORPSE;
  368. //    self->takedamage                = qtrue;            // can still be gibbed
  369.     self->r.contents                = CONTENTS_CORPSE;
  370.     self->takedamage                = qfalse;
  371.  
  372.     self->client->ps.zoomFov        = 0;            // Turn off zooming when we die
  373.     self->client->ps.stats[STAT_GAMETYPE_ITEMS] = 0;
  374.     self->client->ps.pm_flags &= ~(PMF_GOGGLES_ON|PMF_ZOOM_FLAGS);
  375.     self->client->ps.loopSound = 0;
  376.  
  377.     self->s.angles[0]                = 0;
  378.     self->s.angles[2]                = 0;
  379.     self->s.loopSound                = 0;
  380.     self->r.maxs[2]                    = -8;
  381.  
  382.     LookAtKiller (self, inflictor, attacker);
  383.  
  384.     VectorCopy( self->s.angles, self->client->ps.viewangles );
  385.  
  386.     // don't allow respawn until the death anim is done
  387.     // g_forcerespawn may force spawning at some later time
  388.     self->client->respawnTime = level.time + 1700;    
  389.                     
  390.     switch ( hitLocation & (~HL_DISMEMBERBIT) )
  391.     {
  392.         case HL_WAIST:
  393.             if ( rand() %2 )
  394.             {
  395.                 anim = BOTH_DEATH_GROIN_1 + (rand()%2);
  396.             }
  397.             else
  398.             {
  399.                 anim = BOTH_DEATH_GUT_1 + (rand()%2);    // GUT2 is being shot from the back.
  400.             }
  401.             break;
  402.  
  403.         default:            
  404.         case HL_CHEST:
  405.             anim = BOTH_DEATH_CHEST_1 + (rand()%2);
  406.             break;
  407.  
  408.         case HL_CHEST_RT:
  409.             if ( irand(1,10) < 8 )
  410.             {
  411.                 anim = BOTH_DEATH_SHOULDER_RIGHT_1 + (rand()%2);
  412.             }
  413.             else
  414.             {
  415.                 anim = BOTH_DEATH_CHEST_1 + (rand()%2);
  416.             }
  417.             break;
  418.  
  419.         case HL_CHEST_LT:
  420.  
  421.             if ( irand(1,10) < 8 )
  422.             {
  423.                 anim = BOTH_DEATH_SHOULDER_LEFT_1 + (rand()%2);
  424.             }
  425.             else
  426.             {
  427.                 anim = BOTH_DEATH_CHEST_1 + (rand()%2);
  428.             }
  429.  
  430.             break;
  431.  
  432.         case HL_NECK:
  433.             anim = BOTH_DEATH_NECK;
  434.             break;
  435.  
  436.         case HL_HEAD:
  437.             anim = BOTH_DEATH_HEAD_1 + (rand()%2);
  438.             break;
  439.  
  440.         case HL_LEG_UPPER_LT:
  441.             anim = BOTH_DEATH_THIGH_LEFT_1 + (rand()%2);
  442.             break;
  443.  
  444.         case HL_LEG_LOWER_LT:
  445.         case HL_FOOT_LT:
  446.             anim = BOTH_DEATH_LEGS_LEFT_1 + (rand()%3);
  447.             break;
  448.  
  449.         case HL_ARM_LT:
  450.  
  451.             if ( rand()%2 )
  452.                 anim = BOTH_DEATH_ARMS_LEFT_1 + (rand()%2);
  453.             else
  454.                 anim = BOTH_DEATH_SHOULDER_LEFT_1 + (rand()%2);
  455.  
  456.             break;
  457.  
  458.         case HL_ARM_RT:
  459.  
  460.             if ( rand()%2 )
  461.                 anim = BOTH_DEATH_ARMS_RIGHT_1 + (rand()%2);
  462.             else
  463.                 anim = BOTH_DEATH_SHOULDER_RIGHT_1 + (rand()%2);
  464.  
  465.             break;
  466.  
  467.         case HL_LEG_UPPER_RT:
  468.             anim = BOTH_DEATH_THIGH_RIGHT_1 + (rand()%2);
  469.             break;
  470.  
  471.         case HL_LEG_LOWER_RT:
  472.         case HL_FOOT_RT:
  473.             anim = BOTH_DEATH_LEGS_RIGHT_1 + (rand()%3);
  474.             break;
  475.     }
  476.  
  477.     self->client->ps.legsAnim = 
  478.         ( ( self->client->ps.legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
  479.     self->client->ps.torsoAnim = 
  480.         ( ( self->client->ps.torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim;
  481.  
  482.     // If the dismember bit is set then make sure the body queue dismembers
  483.     // the location that was hit
  484.     if ( hitLocation & HL_DISMEMBERBIT )
  485.     {
  486.         CopyToBodyQue (self, hitLocation & (~HL_DISMEMBERBIT), hitDir );
  487.     }
  488.     else
  489.     {
  490.         CopyToBodyQue (self, HL_NONE, hitDir );
  491.     }
  492.  
  493.     // the body can still be gibbed
  494.     self->die = body_die;
  495.  
  496.     trap_LinkEntity (self);
  497. }
  498.  
  499. /*
  500. ================
  501. CheckArmor
  502. ================
  503. */
  504. int CheckArmor (gentity_t *ent, int damage, int dflags)
  505. {
  506.     gclient_t    *client;
  507.     int            save;
  508.     int            count;
  509.  
  510.     if (!damage)
  511.         return 0;
  512.  
  513.     client = ent->client;
  514.  
  515.     if (!client)
  516.         return 0;
  517.  
  518.     if (dflags & DAMAGE_NO_ARMOR)
  519.         return 0;
  520.  
  521.     // armor
  522.     count = client->ps.stats[STAT_ARMOR];
  523.     save = ceil( damage * ARMOR_PROTECTION );
  524.     if (save >= count)
  525.         save = count;
  526.  
  527.     if (!save)
  528.         return 0;
  529.  
  530.     client->ps.stats[STAT_ARMOR] -= save;
  531.  
  532.     return save;
  533. }
  534.  
  535.  
  536. void G_ApplyKnockback( gentity_t *targ, vec3_t newDir, float knockback )
  537. {
  538.     vec3_t    kvel;
  539.     float    mass;
  540.  
  541.     if ( targ->physicsBounce > 0 )    //overide the mass
  542.         mass = targ->physicsBounce;
  543.     else
  544.         mass = 200;
  545.  
  546.     if ( g_gravity.value > 0 )
  547.     {
  548.         VectorScale( newDir, g_knockback.value * (float)knockback / mass * 0.8, kvel );
  549. //        kvel[2] = newDir[2] * g_knockback.value * (float)knockback / mass * 1.5;
  550.     }
  551.     else
  552.     {
  553.         VectorScale( newDir, g_knockback.value * (float)knockback / mass, kvel );
  554.     }
  555.  
  556.     if ( targ->client )
  557.     {
  558.         VectorAdd( targ->client->ps.velocity, kvel, targ->client->ps.velocity );
  559.     }
  560.     else if ( targ->s.pos.trType != TR_STATIONARY && targ->s.pos.trType != TR_LINEAR_STOP )
  561.     {
  562.         VectorAdd( targ->s.pos.trDelta, kvel, targ->s.pos.trDelta );
  563.         VectorCopy( targ->r.currentOrigin, targ->s.pos.trBase );
  564.         targ->s.pos.trTime = level.time;
  565.     }
  566.  
  567.     // set the timer so that the other client can't cancel
  568.     // out the movement immediately
  569.     if ( targ->client && !targ->client->ps.pm_time ) 
  570.     {
  571.         int        t;
  572.  
  573.         t = knockback * 2;
  574.         if ( t < 50 ) {
  575.             t = 50;
  576.         }
  577.         if ( t > 200 ) {
  578.             t = 200;
  579.         }
  580.         targ->client->ps.pm_time = t;
  581.         targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
  582.     }
  583. }
  584.  
  585. /*
  586. ================
  587. RaySphereIntersections
  588. ================
  589. */
  590. int RaySphereIntersections( vec3_t origin, float radius, vec3_t point, vec3_t dir, vec3_t intersections[2] ) {
  591.     float b, c, d, t;
  592.  
  593.     //    | origin - (point + t * dir) | = radius
  594.     //    a = dir[0]^2 + dir[1]^2 + dir[2]^2;
  595.     //    b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
  596.     //    c = (point[0] - origin[0])^2 + (point[1] - origin[1])^2 + (point[2] - origin[2])^2 - radius^2;
  597.  
  598.     // normalize dir so a = 1
  599.     VectorNormalize(dir);
  600.     b = 2 * (dir[0] * (point[0] - origin[0]) + dir[1] * (point[1] - origin[1]) + dir[2] * (point[2] - origin[2]));
  601.     c = (point[0] - origin[0]) * (point[0] - origin[0]) +
  602.         (point[1] - origin[1]) * (point[1] - origin[1]) +
  603.         (point[2] - origin[2]) * (point[2] - origin[2]) -
  604.         radius * radius;
  605.  
  606.     d = b * b - 4 * c;
  607.     if (d > 0) {
  608.         t = (- b + sqrt(d)) / 2;
  609.         VectorMA(point, t, dir, intersections[0]);
  610.         t = (- b - sqrt(d)) / 2;
  611.         VectorMA(point, t, dir, intersections[1]);
  612.         return 2;
  613.     }
  614.     else if (d == 0) {
  615.         t = (- b ) / 2;
  616.         VectorMA(point, t, dir, intersections[0]);
  617.         return 1;
  618.     }
  619.     return 0;
  620. }
  621.  
  622. int G_GetHitLocation(gentity_t *target, vec3_t ppoint, vec3_t dir )
  623. {
  624.     float        fdot;
  625.     float        rdot;
  626.     vec3_t        tangles;
  627.     vec3_t        forward;
  628.     vec3_t        up;
  629.     vec3_t        right;
  630.     vec3_t        distance;
  631.     vec3_t        tcenter;
  632.     vec3_t        temp;
  633.     vec3_t        hit;
  634.  
  635.     // We are only interested in the YAW angle of the target
  636.     VectorSet( tangles, 0, target->client->ps.viewangles[YAW], 0);
  637.  
  638.     // Extract the forward, right, and up vectors
  639.     AngleVectors ( tangles, forward, right, up );
  640.  
  641.     // Determine the center of the target entity
  642.     VectorAdd(target->r.absmin, target->r.absmax, tcenter);
  643.     VectorScale(tcenter, 0.5, tcenter);
  644.  
  645.  
  646. /* NOTE: This would work to figure out shots that go across the front of someone and
  647.          hit the opposite side, but had an error in it when a shot came from either
  648.          the immediate left or right of the player.
  649. */
  650.  
  651.     // Calculate the distnace from the shooter to the target
  652.     VectorCopy ( dir, temp );
  653.     VectorSubtract ( tcenter, ppoint, distance );
  654.  
  655.     // Use that distnace to determine the point of tangent in relation to
  656.     // the center of the player entity
  657.     VectorMA ( ppoint, DotProduct ( temp, distance ), temp, hit );
  658.  
  659.     // Create a vector from the tangent point to the center.  This will
  660.     // be used to determine which side was hit
  661.     VectorSubtract ( tcenter, hit, temp );
  662.     VectorCopy ( temp, distance );
  663.  
  664.     VectorSubtract ( tcenter, ppoint, temp );
  665.     VectorNormalize ( temp );
  666.  
  667.     // Determine the shot in relation to the forward vector
  668.     fdot = DotProduct ( forward, temp );
  669.  
  670.     // Determine the shot in relation to the right vector
  671.     rdot = DotProduct ( right, temp );
  672.  
  673.     if ( distance[2] < -35 )
  674.     {
  675.         return HL_HEAD;
  676.     }
  677.     else if ( distance[2] < -32 )
  678.     {
  679.         return HL_NECK;
  680.     }
  681.     else if ( distance[2] < -27 )
  682.     {
  683.         if ( rdot > 0 )
  684.             return HL_ARM_LT;
  685.  
  686.         return HL_ARM_RT;
  687.     }
  688.     else if ( distance[2] < -3 )
  689.     {
  690.         if ( fdot > 0 )
  691.         {
  692.             if ( rdot > 0 )
  693.             {
  694.                 return HL_CHEST_LT;
  695.             }
  696.  
  697.             return HL_CHEST_RT;
  698.         }
  699.  
  700.         if ( rdot > 0 )
  701.         {
  702.             return HL_BACK_LT;
  703.         }
  704.  
  705.         return HL_BACK_RT;
  706.     }
  707.     else if ( distance[2] < 4 )
  708.     {
  709.         return HL_WAIST;
  710.     }
  711.     else if ( distance[2] < 18 )
  712.     {
  713.         if ( rdot > 0 )
  714.             return HL_LEG_UPPER_LT;
  715.  
  716.         return HL_LEG_UPPER_RT;
  717.     }
  718.     else if ( distance[2] < 33 )
  719.     {
  720.         if ( rdot > 0 )
  721.             return HL_LEG_LOWER_LT;
  722.  
  723.         return HL_LEG_LOWER_RT;
  724.     }
  725.  
  726.     if ( rdot > 0 )
  727.         return HL_FOOT_LT;
  728.  
  729.     return HL_FOOT_RT;
  730. }
  731.  
  732. /*
  733. ============
  734. T_Damage
  735.  
  736. targ        entity that is being damaged
  737. inflictor    entity that is causing the damage
  738. attacker    entity that caused the inflictor to damage targ
  739.     example: targ=monster, inflictor=rocket, attacker=player
  740.  
  741. dir            direction of the attack for knockback
  742. point        point at which the damage is being inflicted, used for headshots
  743. damage        amount of damage being inflicted
  744. knockback    force to be applied against targ as a result of the damage
  745.  
  746. inflictor, attacker, dir, and point can be NULL for environmental effects
  747.  
  748. dflags        these flags are used to control how T_Damage works
  749.     DAMAGE_RADIUS            damage was indirect (from a nearby explosion)
  750.     DAMAGE_NO_ARMOR            armor does not protect from this damage
  751.     DAMAGE_NO_KNOCKBACK        do not affect velocity, just view angles
  752.     DAMAGE_NO_PROTECTION    kills godmode, armor, everything
  753. ============
  754. */
  755.  
  756. int G_Damage ( 
  757.     gentity_t        *targ, 
  758.     gentity_t        *inflictor, 
  759.     gentity_t        *attacker,
  760.     vec3_t            dir, 
  761.     vec3_t            point,
  762.     int                damage,
  763.     int                dflags,
  764.     int                mod,
  765.     int                location
  766.     ) 
  767. {
  768.     gclient_t        *client;
  769.     int                take;
  770.     int                save;
  771.     int                asave;
  772.     int                knockback;
  773.  
  774.     if (!targ->takedamage) 
  775.     {
  776.         return 0;
  777.     }
  778.  
  779.     // See if they are invulnerable
  780.     if ( (mod&0xFF) < MOD_WATER )
  781.     {
  782.         if ( targ->client && (level.time - targ->client->invulnerableTime < g_respawnInvulnerability.integer * 1000) )
  783.         {
  784.             return 0;
  785.         }
  786.     }
  787.  
  788.     // Cant change outfitting after being shot
  789.     if ( targ->client )
  790.     {
  791.         targ->client->noOutfittingChange = qtrue;
  792.     }
  793.  
  794.     if ( !inflictor ) 
  795.     {
  796.         inflictor = &g_entities[ENTITYNUM_WORLD];
  797.     }
  798.     if ( !attacker ) 
  799.     {
  800.         attacker = &g_entities[ENTITYNUM_WORLD];
  801.     }
  802.  
  803.     // shootable doors / buttons don't actually have any health
  804.     if ( targ->s.eType == ET_MOVER ) 
  805.     {
  806.         if ( targ->use && targ->moverState == MOVER_POS1 ) 
  807.         {
  808.             targ->use( targ, inflictor, attacker );
  809.         }
  810.         return 0;
  811.     }
  812.  
  813.     client = targ->client;
  814.  
  815.     if ( client ) 
  816.     {
  817.         if ( client->noclip ) 
  818.         {
  819.             return 0;
  820.         }
  821.     }
  822.  
  823.     if ( !dir ) 
  824.     {
  825.         dflags |= DAMAGE_NO_KNOCKBACK;
  826.     } 
  827.     else 
  828.     {
  829.         VectorNormalize(dir);
  830.     }
  831.  
  832.     knockback = damage;
  833.     if ( knockback > 200 ) 
  834.     {
  835.         knockback = 200;
  836.     }
  837.     if ( targ->flags & FL_NO_KNOCKBACK ) {
  838.         knockback = 0;
  839.     }
  840.     if ( dflags & DAMAGE_NO_KNOCKBACK ) {
  841.         knockback = 0;
  842.     }
  843.  
  844. /*
  845.     // figure momentum add, even if the damage won't be taken
  846.     if ( knockback && targ->client ) 
  847.     {
  848.         G_ApplyKnockback ( targ, dir, knockback );
  849.         vec3_t    kvel;
  850.         float    mass;
  851.  
  852.         mass = 200;
  853.  
  854.         VectorScale (dir, g_knockback.value * (float)knockback / mass, kvel);
  855.         VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity);
  856.  
  857.         // set the timer so that the other client can't cancel
  858.         // out the movement immediately
  859.         if ( !targ->client->ps.pm_time ) {
  860.             int        t;
  861.  
  862.             t = knockback * 2;
  863.             if ( t < 50 ) {
  864.                 t = 50;
  865.             }
  866.             if ( t > 200 ) {
  867.                 t = 200;
  868.             }
  869.             targ->client->ps.pm_time = t;
  870.             targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK;
  871.         }
  872.     }
  873. */
  874.  
  875.     // check for completely getting out of the damage
  876.     if ( !(dflags & DAMAGE_NO_PROTECTION) ) {
  877.  
  878.         // if TF_NO_FRIENDLY_FIRE is set, don't do damage to the target
  879.         // if the attacker was on the same team
  880.         if ( targ != attacker && OnSameTeam (targ, attacker)  ) 
  881.         {
  882.             if ( !g_friendlyFire.integer ) 
  883.             {
  884.                 return 0;
  885.             }
  886.         }
  887.  
  888.         // check for godmode
  889.         if ( targ->flags & FL_GODMODE ) 
  890.         {
  891.             return 0;
  892.         }
  893.     }
  894.  
  895.     if ( damage < 1 ) 
  896.     {
  897.         damage = 1;
  898.     }
  899.  
  900.     take = damage;
  901.     save = 0;
  902.  
  903.     // Be careful with grenades
  904.     if ( attacker == targ )
  905.     {
  906.         take *= 2;
  907.     }
  908.  
  909.     // save some from armor
  910.     asave = CheckArmor (targ, take, dflags);
  911.     take -= asave;
  912.  
  913.     // Teamkill dmage thats not caused by a telefrag?
  914.     if ( g_teamkillDamageMax.integer && mod != MOD_TELEFRAG && !(dflags&DAMAGE_NO_TEAMKILL) )
  915.     {
  916.         if ( level.gametypeData->teams && targ && attacker && targ != attacker )
  917.         {
  918.             // Hurt your own team?
  919.             if ( OnSameTeam ( targ, attacker ) )
  920.             {
  921.                 int actualtake = Com_Clamp ( 0, targ->health, take );
  922.  
  923.                 attacker->client->sess.teamkillDamage       += actualtake;
  924.                 attacker->client->sess.teamkillForgiveTime  = level.time;
  925.             }
  926.         }
  927.     }
  928.  
  929.     // Output hits
  930.     if ( g_logHits.integer && attacker && targ && attacker->client && targ->client )
  931.     {
  932.         G_LogPrintf ( "hit: %i %i %i %i %i: %s hit %s at location %i for %i\n",
  933.                           attacker->s.number,
  934.                           targ->s.number,
  935.                           location,
  936.                           take,
  937.                           asave,
  938.                           attacker->client->pers.netname,
  939.                           targ->client->pers.netname,
  940.                           location,
  941.                           (int)((float)take) );
  942.     }
  943.  
  944.     if ( g_debugDamage.integer ) 
  945.     {
  946.         Com_Printf( "%i: client:%i health:%i damage:%i armor:%i\n", level.time, targ->s.number, targ->health, take, asave );
  947.     }
  948.  
  949.     // add to the damage inflicted on a player this frame
  950.     // the total will be turned into screen blends and view angle kicks
  951.     // at the end of the frame
  952.     if ( client ) 
  953.     {
  954.         if ( attacker ) 
  955.         {
  956.             client->ps.persistant[PERS_ATTACKER] = attacker->s.number;
  957.         } 
  958.         else 
  959.         {
  960.             client->ps.persistant[PERS_ATTACKER] = ENTITYNUM_WORLD;
  961.         }
  962.  
  963.         if ( mod != MOD_WATER )
  964.         {
  965.             client->damage_armor += asave;
  966.             client->damage_blood += take;
  967.         }
  968.  
  969.         client->damage_knockback += knockback;
  970.         
  971.         if ( dir ) 
  972.         {
  973.             VectorCopy ( dir, client->damage_from );
  974.             client->damage_fromWorld = qfalse;
  975.         } 
  976.         else 
  977.         {
  978.             VectorCopy ( targ->r.currentOrigin, client->damage_from );
  979.             client->damage_fromWorld = qtrue;
  980.         }
  981.  
  982.         if (attacker && attacker->client)
  983.         {
  984.             BotDamageNotification(client, attacker);
  985.         }
  986.         else if (inflictor && inflictor->client)
  987.         {
  988.             BotDamageNotification(client, inflictor);
  989.         }
  990.     }
  991.  
  992.     if (targ->client) 
  993.     {
  994.         // set the last client who damaged the target
  995.         targ->client->lasthurt_client = attacker->s.number;
  996.         targ->client->lasthurt_time = level.time;
  997.         targ->client->lasthurt_mod = mod;
  998.     }
  999.  
  1000.     // do the damage
  1001.     if (take)
  1002.     {
  1003.         targ->health = targ->health - take;
  1004.  
  1005.         if ( targ->client )
  1006.         {
  1007.             targ->client->ps.stats[STAT_HEALTH] = targ->health;
  1008.  
  1009.             if ( targ->health > 0 )
  1010.             {
  1011.                 // 45 damage is full slowdown, so..
  1012.                 float slowdown;
  1013.  
  1014.                 slowdown = (float)damage / 20.0f;
  1015.                 slowdown  = Com_Clampf ( 0.0f, 1.0f, slowdown );
  1016.                 slowdown *= 0.75f;
  1017.                 slowdown = 1.0f - slowdown;
  1018.                 
  1019.                 // Slow down the client at bit when they get hit
  1020.                 targ->client->ps.velocity[0] *= slowdown;
  1021.                 targ->client->ps.velocity[1] *= slowdown;
  1022.  
  1023.                 // figure momentum add, even if the damage won't be taken
  1024.                 if ( knockback ) 
  1025.                 {
  1026.                     G_ApplyKnockback ( targ, dir, knockback );
  1027.                 }
  1028.  
  1029.                 // Friendly fire
  1030.                 if ( g_friendlyFire.integer && targ != attacker && OnSameTeam ( targ, attacker ) )
  1031.                 {
  1032.                     vec3_t diff;
  1033.                     
  1034.                     // Make sure the attacker is close enough to hear the guy whining
  1035.                     VectorSubtract ( targ->r.currentOrigin, attacker->r.currentOrigin, diff );
  1036.                     if ( VectorLengthSquared ( diff ) < 800 * 800 )
  1037.                     {
  1038.                         G_VoiceGlobal ( targ, "check_fire", qfalse );
  1039.                     }
  1040.                 }
  1041.             }
  1042.         }
  1043.  
  1044.         if ( targ->health <= 0 )
  1045.         {
  1046.             // Something dismembered?
  1047.             if ( (targ->health < DISMEMBER_HEALTH && !(dflags&DAMAGE_NO_GORE)) || (dflags&DAMAGE_FORCE_GORE) )
  1048.             {
  1049.                 location |= HL_DISMEMBERBIT;
  1050.             }
  1051.  
  1052.             if ( client )
  1053.                 targ->flags |= FL_NO_KNOCKBACK;
  1054.  
  1055.             if (targ->health < -999)
  1056.                 targ->health = -999;
  1057.  
  1058.             targ->enemy = attacker;
  1059.             targ->die (targ, inflictor, attacker, take, mod, location, dir );
  1060.         } 
  1061.         else if ( targ->pain )
  1062.         {
  1063.             targ->pain (targ, attacker, take);
  1064.         }
  1065.     }
  1066.  
  1067.     return take;
  1068. }
  1069.  
  1070. /*
  1071. ============
  1072. CanDamage
  1073.  
  1074. Returns qtrue if the inflictor can directly damage the target.  Used for
  1075. explosions and melee attacks.
  1076. ============
  1077. */
  1078. qboolean CanDamage (gentity_t *targ, vec3_t origin) {
  1079.     vec3_t    dest;
  1080.     trace_t    tr;
  1081.     vec3_t    midpoint;
  1082.  
  1083.     // use the midpoint of the bounds instead of the origin, because
  1084.     // bmodels may have their origin is 0,0,0
  1085.     VectorAdd (targ->r.absmin, targ->r.absmax, midpoint);
  1086.     VectorScale (midpoint, 0.5, midpoint);
  1087.  
  1088.     VectorCopy (midpoint, dest);
  1089.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1090.     if (tr.fraction == 1.0 || tr.entityNum == targ->s.number)
  1091.         return qtrue;
  1092.  
  1093.     // this should probably check in the plane of projection, 
  1094.     // rather than in world coordinate, and also include Z
  1095.     VectorCopy (midpoint, dest);
  1096.     dest[0] += 15.0;
  1097.     dest[1] += 15.0;
  1098.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1099.     if (tr.fraction == 1.0)
  1100.         return qtrue;
  1101.  
  1102.     VectorCopy (midpoint, dest);
  1103.     dest[2] = targ->r.absmax[2];
  1104.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1105.     if (tr.fraction == 1.0)
  1106.         return qtrue;
  1107.  
  1108.     VectorCopy (midpoint, dest);
  1109.     dest[2] = targ->r.absmin[2];
  1110.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1111.     if (tr.fraction == 1.0)
  1112.         return qtrue;
  1113.  
  1114.     VectorCopy (midpoint, dest);
  1115.     dest[0] += 15.0;
  1116.     dest[1] -= 15.0;
  1117.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1118.     if (tr.fraction == 1.0)
  1119.         return qtrue;
  1120.  
  1121.     VectorCopy (midpoint, dest);
  1122.     dest[0] -= 15.0;
  1123.     dest[1] += 15.0;
  1124.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1125.     if (tr.fraction == 1.0)
  1126.         return qtrue;
  1127.  
  1128.     VectorCopy (midpoint, dest);
  1129.     dest[0] -= 15.0;
  1130.     dest[1] -= 15.0;
  1131.     trap_Trace ( &tr, origin, vec3_origin, vec3_origin, dest, ENTITYNUM_NONE, MASK_SOLID);
  1132.     if (tr.fraction == 1.0)
  1133.         return qtrue;
  1134.  
  1135.  
  1136.     return qfalse;
  1137. }
  1138. /*
  1139. ============
  1140. G_MultipleDamageLocations
  1141. ============
  1142. */
  1143. int G_MultipleDamageLocations(int hitLocation)
  1144. {
  1145.  
  1146.     switch ( hitLocation & (~HL_DISMEMBERBIT) )
  1147.     {
  1148.         case HL_FOOT_RT:
  1149.         case HL_FOOT_LT:
  1150.             hitLocation |= (HL_FOOT_RT | HL_FOOT_LT);
  1151.             break;
  1152.         case HL_LEG_UPPER_RT:
  1153.             hitLocation |= (HL_LEG_UPPER_RT | HL_LEG_LOWER_LT);
  1154.             if ( rand() %2 )
  1155.             {
  1156.                 hitLocation |= HL_HAND_RT;
  1157.             }
  1158.             break;
  1159.         case HL_LEG_UPPER_LT:
  1160.             hitLocation |= (HL_LEG_UPPER_LT | HL_LEG_LOWER_RT);
  1161.             if ( rand() %2 )
  1162.             {
  1163.                 hitLocation |= HL_HAND_LT;
  1164.             }
  1165.             break;
  1166.         case HL_LEG_LOWER_RT:
  1167.             hitLocation |= (HL_LEG_LOWER_RT | HL_FOOT_LT);
  1168.             break;
  1169.         case HL_LEG_LOWER_LT:
  1170.             hitLocation |= (HL_LEG_LOWER_LT | HL_FOOT_RT);
  1171.             break;
  1172.         case HL_HAND_RT:
  1173.             hitLocation |= HL_HAND_RT;
  1174.             break;
  1175.         case HL_HAND_LT:
  1176.             hitLocation |= HL_HAND_LT;
  1177.             break;
  1178.         case HL_ARM_RT:
  1179.             hitLocation |= (HL_ARM_RT | HL_LEG_UPPER_RT) ;
  1180.             break;
  1181.         case HL_ARM_LT:
  1182.             hitLocation |= (HL_ARM_LT | HL_LEG_UPPER_LT) ;
  1183.             break;
  1184.         case HL_HEAD:
  1185.             hitLocation |= HL_HEAD ;
  1186.             if ( rand() %2 )
  1187.             {
  1188.                 hitLocation |= HL_ARM_RT;
  1189.             }
  1190.             else
  1191.             {
  1192.                 hitLocation |= HL_ARM_LT;
  1193.             }
  1194.             break;
  1195.         case HL_WAIST:
  1196.             hitLocation |= (HL_LEG_UPPER_RT | HL_LEG_UPPER_LT) ;
  1197.  
  1198.             if ( rand() %2 )
  1199.             {
  1200.                 if ( rand() %2 )
  1201.                 {
  1202.                     hitLocation |= HL_HAND_RT;
  1203.                 }
  1204.                 else
  1205.                 {
  1206.                     hitLocation |= HL_HAND_LT;
  1207.                 }
  1208.             }
  1209.             break;
  1210.         case HL_BACK_RT:
  1211.         case HL_CHEST_RT:
  1212.             hitLocation |= HL_ARM_RT;
  1213.             hitLocation |= HL_HEAD;
  1214.             break;
  1215.         case HL_BACK_LT:
  1216.         case HL_CHEST_LT:
  1217.             hitLocation |= HL_ARM_LT;
  1218.             hitLocation |= HL_HEAD;
  1219.             break;
  1220.         case HL_BACK:
  1221.         case HL_CHEST:
  1222.             hitLocation |= (HL_ARM_RT | HL_ARM_LT);
  1223.             hitLocation |= HL_HEAD;
  1224.             break;
  1225.  
  1226.     }
  1227.  
  1228.     return (hitLocation);
  1229. }
  1230.  
  1231.  
  1232. /*
  1233. ============
  1234. G_RadiusDamage
  1235. ============
  1236. */
  1237. qboolean G_RadiusDamage ( 
  1238.     vec3_t        origin, 
  1239.     gentity_t*    attacker, 
  1240.     float        damage, 
  1241.     float        radius,
  1242.     gentity_t*    ignore, 
  1243.     int            power, 
  1244.     int            dflags,
  1245.     int            mod
  1246.     ) 
  1247. {
  1248.     float        points, dist;
  1249.     gentity_t    *ent, *tent;
  1250.     int            entityList[MAX_GENTITIES];
  1251.     int            numListedEntities;
  1252.     vec3_t        mins, maxs;
  1253.     vec3_t        v;
  1254.     vec3_t        dir;
  1255.     int            i, e;
  1256.     qboolean    hitClient = qfalse;
  1257.  
  1258.     if ( radius < 1 ) 
  1259.     {
  1260.         radius = 1;
  1261.     }
  1262.  
  1263.     for ( i = 0 ; i < 3 ; i++ ) 
  1264.     {
  1265.         mins[i] = origin[i] - radius;
  1266.         maxs[i] = origin[i] + radius;
  1267.     }
  1268.  
  1269.     numListedEntities = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
  1270.  
  1271.     for ( e = 0 ; e < numListedEntities ; e++ ) 
  1272.     {
  1273.         ent = &g_entities[entityList[ e ]];
  1274.  
  1275.         if (ent == ignore)
  1276.         {
  1277.             continue;
  1278.         }
  1279.         
  1280.         if (!ent->takedamage)
  1281.         {
  1282.             continue;
  1283.         }
  1284.  
  1285.         // find the distance from the edge of the bounding box
  1286.         for ( i = 0 ; i < 3 ; i++ ) 
  1287.         {
  1288.             if ( origin[i] < ent->r.absmin[i] ) 
  1289.             {
  1290.                 v[i] = ent->r.absmin[i] - origin[i];
  1291.             } 
  1292.             else if ( origin[i] > ent->r.absmax[i] ) 
  1293.             {
  1294.                 v[i] = origin[i] - ent->r.absmax[i];
  1295.             } 
  1296.             else 
  1297.             {
  1298.                 v[i] = 0;
  1299.             }
  1300.         }
  1301.  
  1302.         dist = VectorLength( v );
  1303.         if ( dist >= radius ) 
  1304.         {
  1305.             continue;
  1306.         }
  1307.  
  1308.         points = damage * ( 1.0 - powf((dist / radius), power));
  1309.  
  1310.         if( CanDamage (ent, origin) ) 
  1311.         {
  1312.             int        location;
  1313.             int        weapon;
  1314.             vec3_t    hitdir;
  1315.             int        d;
  1316.  
  1317.             VectorSubtract (ent->r.currentOrigin, origin, dir);
  1318.             // push the center of mass higher than the origin so players
  1319.             // get knocked into the air more
  1320.  
  1321.             location = HL_NONE;
  1322.             if ( ent->client )
  1323.             {
  1324.                 VectorNormalize ( dir );                                
  1325.                 VectorCopy(dir, hitdir);
  1326.                 dir[2] = 0;
  1327.                 location = G_GetHitLocation ( ent, origin, dir );
  1328.                 location = G_MultipleDamageLocations ( location );
  1329.             }
  1330.  
  1331.             d = G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS|DAMAGE_NO_ARMOR|dflags, mod, location );
  1332.  
  1333.             if ( d && ent->client )
  1334.             {
  1335.                 // Only one of the grenade hits will count for tk damage
  1336.                 dflags |= DAMAGE_NO_TEAMKILL;
  1337.  
  1338.                 // Put some procedural gore on the target.
  1339.                 tent = G_TempEntity( origin, EV_EXPLOSION_HIT_FLESH );
  1340.                 
  1341.                 // send entity and direction
  1342.                 tent->s.eventParm = DirToByte( hitdir );
  1343.                 if (ignore && ignore->s.weapon)
  1344.                 {
  1345.                     weapon = ignore->s.weapon;        // Weapon type number
  1346.                 }
  1347.                 else if (points >= 10)
  1348.                 {    // dangerous weapon
  1349.                     weapon = WP_SMOHG92_GRENADE;
  1350.                 }
  1351.                 else
  1352.                 {    // Just a flesh wound
  1353.                     weapon = WP_M84_GRENADE;
  1354.                 }
  1355.                 tent->s.otherEntityNum2 = ent->s.number;            // Victim entity number
  1356.  
  1357.                 // Pack the shot info into the temp end for gore
  1358.                 tent->s.time  = weapon + ((((int)ent->s.apos.trBase[YAW]&0x7FFF) % 360) << 16);        
  1359.                 if ( attacker->s.eFlags & EF_ALT_FIRING )
  1360.                 {
  1361.                     tent->s.time += (ATTACK_ALTERNATE<<8);
  1362.                 }
  1363.                 VectorCopy ( ent->r.currentOrigin, tent->s.angles );
  1364.                 SnapVector ( tent->s.angles );
  1365.             }
  1366.         }
  1367.     }
  1368.  
  1369.     return hitClient;
  1370. }
  1371.